home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / misc / pclta-1.000 / pclta-1 / hostappl / applmsg.c next >
Encoding:
C/C++ Source or Header  |  1996-03-18  |  36.8 KB  |  1,085 lines

  1. /*
  2.  * applmsg.c,v 1.0 1996/03/18 14:18:33 miksic Exp
  3.  */
  4.  
  5. /* APPLMSG.C -- LonWorks host application message handler.
  6.  * Copyright (c) 1993 by Echelon Corporation.
  7.  * All Rights Reserved.
  8.  *
  9.  * Handle application messages, network variable messages and network
  10.  * management messages addressed to the application.
  11.  */
  12.  
  13. #include "ni_msg.h"
  14. #include "ni_mgmt.h"
  15. #include "hauif.h"
  16. #include <stdio.h>
  17. #include <fcntl.h>
  18. #include "conio.h"
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include <unistd.h>
  23.  
  24. /*************************************************************
  25.  *
  26.  *          Declare network variable configuration table
  27.  *
  28.  *************************************************************/
  29.  
  30. #define NUM_NVS 8
  31.             /* Number of Network Variable table entries on this node */
  32.  
  33. const int num_nvs = NUM_NVS;          // for external references
  34. nv_struct nv_config_table[ NUM_NVS ]  // configuration table
  35.     = {
  36. /*        selhi  dir     prio  sello  addridx   auth  svc   trnarnd    */
  37.         { 0x3F, NV_OUT, FALSE, 0xFF, NULL_IDX, FALSE, ACKD, FALSE },
  38.         { 0x3F, NV_OUT, FALSE, 0xFE, NULL_IDX, FALSE, ACKD, FALSE },
  39.         { 0x3F, NV_OUT, FALSE, 0xFD, NULL_IDX, FALSE, ACKD, FALSE },
  40.         { 0x3F, NV_OUT, FALSE, 0xFC, NULL_IDX, FALSE, ACKD, FALSE },
  41.         { 0x3F, NV_IN , FALSE, 0xFB, NULL_IDX, FALSE, ACKD, FALSE },
  42.         { 0x3F, NV_IN , FALSE, 0xFA, NULL_IDX, FALSE, ACKD, FALSE },
  43.         { 0x3F, NV_IN , FALSE, 0xF9, NULL_IDX, FALSE, ACKD, FALSE },
  44.         { 0x3F, NV_IN , FALSE, 0xF8, NULL_IDX, FALSE, ACKD, FALSE }
  45.     };                                     // saved to disk
  46.  
  47.  
  48. /*************************************************************
  49.  *
  50.  *          Declare SNVT self identification storage
  51.  *
  52.  *************************************************************/
  53.  
  54. /* There are eight Network Variables and three message tags defined
  55.    These are the equivalent Neuron C declarations:
  56.  
  57.     #pragma enable_sd_nv_names
  58.     #pragma set_node_sd_string "Sample host application program"
  59.  
  60.     network output sd_string( "ASCII string output NV" )
  61.             SNVT_str_asc  NV_string_out;
  62.     network output sd_string( "Discrete output NV" )
  63.             SNVT_lev_disc NV_disc_out;
  64.     network output sd_string( "Continuous output NV" )
  65.             SNVT_lev_cont NV_cont_out;
  66.     network output sd_string( "Floating count output NV" )
  67.             SNVT_count_f  NV_float_out;
  68.  
  69.     network input sd_string( "ASCII string input NV" )
  70.             SNVT_str_asc   NV_string_in;
  71.     network input sd_string( "Discrete input NV" )
  72.             SNVT_lev_disc  NV_disc_in;
  73.     network input sd_string( "Continuous input NV" )
  74.             SNVT_lev_cont  NV_cont_in;
  75.     network input sd_string( "Floating count input NV" )
  76.             SNVT_count_f   NV_float_in;
  77.  
  78.     msg_tag tag_1;
  79.     msg_tag tag_2;
  80.     msg_tag tag_3;
  81.  
  82. */
  83.  
  84. // Network variable names
  85.  
  86. #define SO_name    "NV_string_out"
  87. #define DO_name    "NV_disc_out"
  88. #define CO_name    "NV_cont_out"
  89. #define FO_name    "NV_float_out"
  90. #define SI_name    "NV_string_in"
  91. #define DI_name    "NV_disc_in"
  92. #define CI_name    "NV_cont_in"
  93. #define FI_name    "NV_float_in"
  94.  
  95. // Self-documentation strings
  96.  
  97. #define SO_doc    "ASCII string output NV"
  98. #define DO_doc    "Discrete output NV"
  99. #define CO_doc    "Continuous output NV"
  100. #define FO_doc    "Floating count output NV"
  101. #define SI_doc    "ASCII string input NV"
  102. #define DI_doc    "Discrete input NV"
  103. #define CI_doc    "Continuous input NV"
  104. #define FI_doc    "Floating count input NV"
  105.  
  106. #define Node_doc  "Sample host application program"
  107.  
  108. const struct {
  109.     snvt_struct_v0      header;            // Version 0 SNVT_struct
  110.     snvt_desc_struct    string_out_desc;
  111.     snvt_desc_struct    disc_out_desc;
  112.     snvt_desc_struct    cont_out_desc;
  113.     snvt_desc_struct    float_out_desc;
  114.     snvt_desc_struct    string_in_desc;
  115.     snvt_desc_struct    disc_in_desc;
  116.     snvt_desc_struct    cont_in_desc;
  117.     snvt_desc_struct    float_in_desc;
  118.  
  119.     char                node_doc_string[ sizeof( Node_doc ) ];
  120.  
  121.     snvt_ext_rec_mask   string_out_mask;
  122.     char                string_out_name[ sizeof( SO_name ) ];
  123.     char                string_out_doc[ sizeof( SO_doc ) ];
  124.     snvt_ext_rec_mask   disc_out_mask;
  125.     char                disc_out_name[ sizeof( DO_name ) ];
  126.     char                disc_out_doc[ sizeof( DO_doc ) ];
  127.     snvt_ext_rec_mask   cont_out_mask;
  128.     char                cont_out_name[ sizeof( CO_name ) ];
  129.     char                cont_out_doc[ sizeof( CO_doc ) ];
  130.     snvt_ext_rec_mask   float_out_mask;
  131.     char                float_out_name[ sizeof( FO_name ) ];
  132.     char                float_out_doc[ sizeof( FO_doc ) ];
  133.     snvt_ext_rec_mask   string_in_mask;
  134.     char                string_in_name[ sizeof( SI_name ) ];
  135.     char                string_in_doc[ sizeof( SI_doc ) ];
  136.     snvt_ext_rec_mask   disc_in_mask;
  137.     char                disc_in_name[ sizeof( DI_name ) ];
  138.     char                disc_in_doc[ sizeof( DI_doc ) ];
  139.     snvt_ext_rec_mask   cont_in_mask;
  140.     char                cont_in_name[ sizeof( CI_name ) ];
  141.     char                cont_in_doc[ sizeof( CI_doc ) ];
  142.     snvt_ext_rec_mask   float_in_mask;
  143.     char                float_in_name[ sizeof( FI_name ) ];
  144.     char                float_in_doc[ sizeof( FI_doc ) ];
  145.  
  146. } SNVT_info = {
  147.                                                   // SNVT structure
  148.     { sizeof( SNVT_info ) >> 8,    // length_hi
  149.       sizeof( SNVT_info ) & 0xFF,  // length_lo
  150.       NUM_NVS,                  // num_netvars
  151.       0,                        // version
  152.       3                         // mtag_count
  153.     },
  154.  
  155.     // These SNVT descriptors have ext_rec, nv_service_type_config,
  156.     // nv_priority_config and nv_auth_config set.  In addition, the inputs
  157.     // have nv_polled set, since the application polls them.
  158.  
  159.     { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_str_asc },    // SNVT descriptors
  160.     { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_lev_disc },
  161.     { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_lev_cont },
  162.     { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_count_f  },
  163.     { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_str_asc  },
  164.     { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_lev_disc },
  165.     { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_lev_cont },
  166.     { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_count_f  },
  167.  
  168.     Node_doc,                       // node self-documentation string
  169.  
  170.     // These extension record masks have nm and sd set
  171.     // For Microsoft C, the initializers are hex bytes, since odd-length
  172.     // bitfields are not allowed.
  173.  
  174. #ifdef _MSC_VER
  175.     { 0x30 },
  176. #else
  177.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  178. #endif
  179.     SO_name,                        // name
  180.     SO_doc,                         // self-doc
  181.  
  182. #ifdef _MSC_VER
  183.     { 0x30 },
  184. #else
  185.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  186. #endif
  187.     DO_name,                        // name
  188.     DO_doc,                         // self-doc
  189.  
  190. #ifdef _MSC_VER
  191.     { 0x30 },
  192. #else
  193.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  194. #endif
  195.     CO_name,                        // name
  196.     CO_doc,                         // self-doc
  197.  
  198. #ifdef _MSC_VER
  199.     { 0x30 },
  200. #else
  201.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  202. #endif
  203.     FO_name,                        // name
  204.     FO_doc,                         // self-doc
  205.  
  206. #ifdef _MSC_VER
  207.     { 0x30 },
  208. #else
  209.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  210. #endif
  211.     SI_name,                        // name
  212.     SI_doc,                         // self-doc
  213.  
  214. #ifdef _MSC_VER
  215.     { 0x30 },
  216. #else
  217.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  218. #endif
  219.     DI_name,                        // name
  220.     DI_doc,                         // self-doc
  221.  
  222. #ifdef _MSC_VER
  223.     { 0x30 },
  224. #else
  225.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  226. #endif
  227.     CI_name,                        // name
  228.     CI_doc,                         // self-doc
  229.  
  230. #ifdef _MSC_VER
  231.     { 0x30 },
  232. #else
  233.     { 0, 0, 1, 1, 0, 0 },           // extension record mask
  234. #endif
  235.     FI_name,                        // name
  236.     FI_doc                          // self-doc
  237. };
  238.  
  239. /*************************************************************
  240.  *
  241.  *          Declare network variable storage
  242.  *
  243.  *************************************************************/
  244.  
  245.  
  246. // prototypes for I/O functions
  247.  
  248. void print_asc( byte * );     // print routines for SNVT values
  249. void print_disc( byte * );
  250. void print_cont( byte * );
  251. void print_float( byte * );
  252. void read_asc( byte * );      // read SNVT values from keyboard
  253. void read_disc( byte * );
  254. void read_cont( byte * );
  255. void read_float( byte * );
  256.  
  257. network_variable nv_value_table[ NUM_NVS ] =  {  // RAM storage for NVs
  258.      { 31,  NV_OUT, SNVT_info.string_out_name, print_asc,  read_asc   },
  259.      {  1,  NV_OUT, SNVT_info.disc_out_name,   print_disc, read_disc  },
  260.      {  1,  NV_OUT, SNVT_info.cont_out_name,   print_cont, read_cont  },
  261.      {  4,  NV_OUT, SNVT_info.float_out_name,  print_float,read_float },
  262.      { 31,  NV_IN,  SNVT_info.string_in_name,  print_asc,  read_asc   },
  263.      {  1,  NV_IN,  SNVT_info.disc_in_name,    print_disc, read_disc  },
  264.      {  1,  NV_IN,  SNVT_info.cont_in_name,    print_cont, read_cont  },
  265.      {  4,  NV_IN,  SNVT_info.float_in_name,   print_float,read_float }
  266. };
  267.  
  268.         // Statistics accumulators for received traffic
  269.  
  270. unsigned num_messages       = 0;
  271. unsigned num_polls          = 0;
  272. unsigned num_updates        = 0;
  273. unsigned long data_length   = 0;
  274.  
  275. boolean report_flag  = TRUE;     // report incoming application msgs
  276. boolean verbose_flag = FALSE;    // display all network interface msgs
  277. boolean online_flag  = TRUE;     // This node is on-line
  278.  
  279. RcvAddrDtl     last_rcv_addr;    // for debugging
  280. boolean        last_rcv_auth;
  281.  
  282.        // Utility function to get an nv_index from a message
  283.        // 2nd arg is pointer to pointer to next byte after nv_index
  284.  
  285. word handle_nv_index( MsgData * in_data, void ** next_byte_ptr );
  286.  
  287. extern boolean                      // define forward references
  288.     handle_update_nv_cnfg( MsgData *, ServiceType ),
  289.     handle_query_nv_cnfg( MsgData *, ServiceType ),
  290.     handle_set_mode( MsgData * ),
  291.     handle_query_SNVT( MsgData *, ServiceType ),
  292.     handle_NV_fetch( MsgData *, ServiceType ),
  293.     handle_netvar_msg( MsgData *, ServiceType, int in_length, boolean auth ),
  294.     handle_explicit_msg( MsgData *, ServiceType, int in_length,
  295.             boolean in_auth );
  296.  
  297. /*************************************************************
  298.  *
  299.  *          Handle incoming messages to this node -
  300.  *          called from main event loop when message is received
  301.  *
  302.  *************************************************************/
  303.  
  304. boolean process_msg( ServiceType    service,
  305.                      RcvAddrDtl   * address,
  306.                      MsgData      * in_data,
  307.                      int            in_length,
  308.                      boolean        in_auth ) {
  309.  
  310.           /* handle incoming messages addressed to this node */
  311.           /* return TRUE if prompt should be redisplayed */
  312.  
  313.     last_rcv_addr = * address;        // save for debug purposes
  314.  
  315.     switch( in_data->exp.code ) {        // dispatch on message code
  316.  
  317.     case NM_update_nv_cnfg:
  318.         return handle_update_nv_cnfg( in_data, service );
  319.  
  320.     case NM_query_nv_cnfg:
  321.         return handle_query_nv_cnfg( in_data, service );
  322.  
  323.     case NM_set_node_mode:
  324.         return handle_set_mode( in_data );
  325.  
  326.     case NM_query_SNVT:
  327.         return handle_query_SNVT( in_data, service );
  328.  
  329.     case NM_wink:
  330.         if( report_flag )printf( "Received Wink network mgmt msg\n" );
  331.         printf( "\a" );      // Ding!
  332.         return report_flag;
  333.  
  334.     case NM_NV_fetch:
  335.         return handle_NV_fetch( in_data, service );
  336.  
  337.     default:    /* handle all other messages here */
  338.  
  339.         if( in_data->unv.must_be_one )         // This is a net var
  340.              return handle_netvar_msg( in_data, service, in_length, in_auth );
  341.                                                // This is an explicit msg
  342.         else return handle_explicit_msg( in_data, service, in_length, in_auth );
  343.  
  344.     }               // end switch
  345. }
  346.  
  347. /*************************************************************
  348.  *
  349.  *          Handle incoming message to update NV config table
  350.  *
  351.  *************************************************************/
  352.  
  353. boolean handle_update_nv_cnfg( MsgData * in_data, ServiceType service ) {
  354.  
  355.     nv_struct                   * nv_cnfg_ptr;
  356.     word                          nv_index;
  357.     MsgData                       response;
  358.     NI_Code                       ni_error;
  359.  
  360.     // When an update_nv_cnfg message is received, the new NV config
  361.     // is copied to the NV config table of this node
  362.  
  363.     nv_index =  handle_nv_index( in_data, ( void * )& nv_cnfg_ptr );
  364.                                 // get requested index from msg
  365.  
  366.     if( nv_index >= NUM_NVS ) {   // too big an index
  367.         response.exp.code = NM_update_nv_cnfg_fail;
  368.     } else {
  369.         response.exp.code = NM_update_nv_cnfg_succ;
  370.         nv_config_table[ nv_index ] = * nv_cnfg_ptr;
  371.             // save nv config table entry
  372.     }
  373.  
  374.     if( service == REQUEST ) ni_error = ni_send_response( &response, 1 );
  375.     if( report_flag ) printf(
  376.         "Received Update NV config network mgmt msg for index %d\n",
  377.             nv_index );
  378.     if( service == REQUEST )
  379.         ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  380.         "sending response" );
  381.     return report_flag;
  382. }
  383.  
  384. /*************************************************************
  385.  *
  386.  *          Handle incoming message to query NV config table
  387.  *
  388.  *************************************************************/
  389.  
  390. boolean handle_query_nv_cnfg( MsgData * in_data, ServiceType service ) {
  391.  
  392.     word     nv_index;
  393.     NM_query_nv_cnfg_response   nv_cnfg_rsp_msg;
  394.     int      out_length;
  395.     NI_Code  ni_error;
  396.  
  397.     // When a query_nv_cnfg message is received, the corresponding
  398.     // entry in the NV config table of this node is returned in a
  399.     // response
  400.  
  401.     if( service != REQUEST ) return FALSE;
  402.     nv_index = handle_nv_index( in_data, NULL );
  403.                            // get requested nv_index from message
  404.  
  405.     if( nv_index >= NUM_NVS ) {   // too big an index
  406.         nv_cnfg_rsp_msg.code = NM_query_nv_cnfg_fail;
  407.         out_length = 1;
  408.     } else {
  409.         nv_cnfg_rsp_msg.code = NM_query_nv_cnfg_succ;
  410.         nv_cnfg_rsp_msg.nv_cnfg = nv_config_table[ nv_index ];
  411.                    // get nv config table entry
  412.         out_length = sizeof( NM_query_nv_cnfg_response );
  413.     }
  414.     ni_error = ni_send_response( ( MsgData * ) &nv_cnfg_rsp_msg, out_length );
  415.     if( report_flag ) printf(
  416.         "Received Query NV config network mgmt msg for index %d\n",
  417.             nv_index );
  418.     ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  419.         "sending response" );
  420.     return report_flag;
  421. }
  422.  
  423. /*************************************************************
  424.  *
  425.  *      Handle incoming message to set the mode of this node
  426.  *
  427.  *************************************************************/
  428.  
  429. boolean handle_set_mode( MsgData * in_data ) {
  430.  
  431.     extern ExpAppBuffer msg_out;   /* Outgoing message buffer   */
  432.     NI_Code             ni_error;
  433.  
  434.     // When a set_node_mode (on/off) line is received, the corresponding
  435.     // command is sent down to the network interface
  436.  
  437.     online_flag = ( in_data->exp.data[ 0 ] == APPL_ONLINE );
  438.     ni_error = ni_send_immediate( online_flag ? niONLINE : niOFFLINE );
  439.  
  440.     if( report_flag ) printf( "Received Set Node Mode network mgmt msg" );
  441.     if( handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  442.         "downlink mode change" ) ) return TRUE;
  443.  
  444.     if( report_flag )printf( " - set host node to %sline\n",
  445.          online_flag ? "on" : "off" );
  446.     return report_flag;
  447. }
  448.  
  449. /*************************************************************
  450.  *
  451.  *      Handle incoming message to query this node's SNVT info
  452.  *
  453.  *************************************************************/
  454.  
  455. boolean handle_query_SNVT( MsgData * in_data, ServiceType service ) {
  456.  
  457.     int         out_length;
  458.     MsgData     response;
  459.     NI_Code     ni_error;
  460.     NM_query_SNVT_request * query_SNVT_req_msg;
  461.     union {
  462.         word        offset;
  463.         struct {
  464.             byte    lo;
  465.             byte    hi;
  466.         } bytes;
  467.     } o;
  468.  
  469.     if( service != REQUEST ) return FALSE;
  470.     query_SNVT_req_msg = ( NM_query_SNVT_request * ) in_data;
  471.  
  472.         // get the offset in Intel byte-ordering
  473.  
  474.     o.bytes.hi = query_SNVT_req_msg->offset_hi;
  475.     o.bytes.lo = query_SNVT_req_msg->offset_lo;
  476.     out_length = query_SNVT_req_msg->count; // number of bytes requested
  477.  
  478.     if( o.offset + out_length > sizeof( SNVT_info ) ) {
  479.          response.exp.code = NM_query_SNVT_fail;
  480.          out_length = 1;            // invalid request
  481.     } else {
  482.         response.exp.code = NM_query_SNVT_succ;
  483.         memcpy( response.exp.data, ( byte * ) & SNVT_info + o.offset,
  484.             out_length );   // copy data from the SNVT table to the response
  485.         out_length++;       // for the code
  486.     }
  487.  
  488.     ni_error = ni_send_response( &response, out_length );
  489.  
  490.     if( report_flag )printf( "Received Query SNVT network mgmt msg\n" );
  491.     ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  492.         "sending response" );
  493.     return report_flag;
  494. }
  495.  
  496. /*************************************************************
  497.  *
  498.  *      Handle incoming NM message to fetch the value of an NV
  499.  *
  500.  *************************************************************/
  501.  
  502. boolean handle_NV_fetch( MsgData * in_data, ServiceType service ) {
  503.  
  504.     word    nv_index;
  505.     MsgData response;
  506.     int     out_length;
  507.     network_variable * nv_value_ptr;
  508.     NI_Code ni_error;
  509.  
  510.     if( service != REQUEST ) return FALSE;
  511.  
  512.      // When an NV_fetch message is received, value is fetched
  513.     nv_index = handle_nv_index( in_data, NULL );
  514.                         // get requested NV index from msg
  515.     if( nv_index >= NUM_NVS ) {
  516.         response.exp.code = NM_NV_fetch_fail;
  517.         out_length = 1;
  518.     } else {          // construct a response
  519.         nv_value_ptr = & nv_value_table[ nv_index ];
  520.         response.exp.code = NM_NV_fetch_succ;
  521.         response.exp.data[ 0 ] = nv_index;
  522.         memcpy( &response.exp.data[ 1 ], nv_value_ptr->data,
  523.                 nv_value_ptr->size );
  524.         out_length = nv_value_ptr->size + 2;   // add code and index
  525.     }
  526.  
  527.     ni_error = ni_send_response( &response, out_length );
  528.     if( report_flag ) printf(
  529.         "Received NV fetch network mgmt msg for %s\n", nv_value_ptr->name );
  530.     ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  531.          "sending response" );
  532.     return report_flag;
  533. }
  534.  
  535. /*************************************************************
  536.  *
  537.  *      match_nv_cnfg - find an entry in NV config table
  538.  *      returns index of entry, or -1 if not found
  539.  *
  540.  *************************************************************/
  541.  
  542. static int match_nv_cnfg( UnprocessedNV * in_nv ) {
  543.  
  544.     nv_struct   * nv_cnfg_ptr;
  545.     int         nv_index;
  546.     nv_cnfg_ptr = nv_config_table;       // point to NV config table
  547.  
  548.     for( nv_index = 0; nv_index < NUM_NVS; nv_index++ ) {
  549.         if( in_nv->NV_selector_lo == nv_cnfg_ptr->selector_lo
  550.         &&  in_nv->NV_selector_hi == nv_cnfg_ptr->selector_hi
  551.         &&  in_nv->direction == nv_cnfg_ptr->direction )
  552.             return nv_index;
  553.         nv_cnfg_ptr++;               // next config table entry
  554.     }
  555.     return -1;          // not found - return error
  556. }
  557.  
  558. /*************************************************************
  559.  *
  560.  *          Handle incoming NV messages to this node
  561.  *
  562.  *************************************************************/
  563.  
  564. boolean handle_netvar_msg( MsgData    * in_data,
  565.                            ServiceType  service,
  566.                            int          in_length,
  567.                            boolean      in_auth ) {
  568.  
  569.     nv_struct         * nv_cnfg_ptr;
  570.     network_variable  * nv_value_ptr;
  571.     int                 nv_index;
  572.     int                 out_length;
  573.     MsgData             response;
  574.     NI_Code             ni_error;
  575.     boolean             auth_OK;
  576.  
  577.     // Find this NV in the NV config table
  578.     nv_index = match_nv_cnfg( &in_data->unv );
  579.  
  580.     if( nv_index >= 0 ) {       // found the NV
  581.         nv_cnfg_ptr = &nv_config_table[ nv_index ];
  582.                         // point to NV config table
  583.         nv_value_ptr = & nv_value_table[ nv_index ];
  584.                         // point to NV data table
  585.         auth_OK = in_auth || !nv_cnfg_ptr->auth;
  586.         // Message is authentic if it was authenticated by the Neuron or
  587.         // authentication is not configured for this NV
  588.     }
  589.  
  590.     if( service == REQUEST ) {    // it's an NV poll
  591.         response.unv.NV_selector_hi = in_data->unv.NV_selector_hi;
  592.         response.unv.direction = ~ in_data->unv.direction;
  593.             // reverse the direction bit to send it back
  594.         response.unv.NV_selector_lo = in_data->unv.NV_selector_lo;
  595.         response.unv.must_be_one = 1;
  596.  
  597.         if( nv_index >= 0 && auth_OK && online_flag ) {
  598.                        // there was a match
  599.             memcpy( response.unv.data, nv_value_ptr->data, nv_value_ptr->size );
  600.                     // fetch the value
  601.             out_length = nv_value_ptr->size + 2;      // including selector
  602.             num_polls++;
  603.         } else out_length = 2;       // no match or off-line, respond anyway
  604.  
  605.         ni_error = ni_send_response( &response, out_length );
  606.                     // add the selector size
  607.         if( report_flag && nv_index >= 0 ) printf( "Received poll for %s\n",
  608.                 nv_value_ptr->name );
  609.  
  610.         ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  611.             "sending response" );
  612.         return report_flag;
  613.     }
  614.  
  615.     // Come here if it's not a poll
  616.     in_length -= 2;        // subtract out the selector size
  617.  
  618.     if( nv_index < 0                      // NV not found
  619.       || !auth_OK                         // failed authentication
  620.       || in_length != nv_value_ptr->size )  // size mismatch
  621.       return FALSE;                       // done if not a valid update
  622.  
  623.     memcpy( nv_value_ptr->data, in_data->unv.data, in_length );
  624.            // update NV
  625.     num_updates++;
  626.     if( report_flag )
  627.         printf( "Updated %s with : ", nv_value_ptr->name );
  628.          nv_value_ptr->print_func( nv_value_ptr->data );
  629.  
  630.     return report_flag;
  631. }
  632.  
  633. /*************************************************************
  634.  *
  635.  *    Internal routine to update the value of a network variable
  636.  *
  637.  *************************************************************/
  638.  
  639. static void update_nv_value( int nv_index,
  640.                       byte * data,
  641.                       int    size ) {
  642.  
  643.     network_variable  * nv_value_ptr;
  644.  
  645.     nv_value_ptr = & nv_value_table[ nv_index ];  // point to NV data table
  646.     if( size != nv_value_ptr->size ) return;
  647.             // Reject update if wrong size
  648.     memcpy( nv_value_ptr->data, data, size );   // update the NV value
  649.  
  650.     num_updates++;
  651.     printf( "Updated %s with : ", nv_value_ptr->name );
  652.     nv_value_ptr->print_func( nv_value_ptr->data );
  653. }
  654.  
  655. /*************************************************************
  656.  *
  657.  *    Handle incoming NV poll responses
  658.  *
  659.  *************************************************************/
  660.  
  661. void handle_netvar_poll_response(
  662.        UnprocessedNV * in_nv,
  663.        int          in_length,
  664.        int          nv_index ) {
  665.  
  666.     nv_struct         * nv_cnfg_ptr;
  667.  
  668.     if( report_flag )printf( "Received network variable poll response\n" );
  669.     // Match on direction and selector bits ( not the first bit )
  670.  
  671.     nv_cnfg_ptr = &nv_config_table[ nv_index ];   // point to NV config table
  672.  
  673.     if( in_nv->NV_selector_lo != nv_cnfg_ptr->selector_lo ) return;
  674.     if( in_nv->NV_selector_hi != nv_cnfg_ptr->selector_hi ) return;
  675.     if( in_nv->direction != nv_cnfg_ptr->direction ) return;
  676.  
  677.     update_nv_value( nv_index, in_nv->data, in_length - 2 );
  678.         // data size is msg size less selector size
  679. }
  680.  
  681. /*************************************************************
  682.  *
  683.  *          Handle incoming explicit messages to this node
  684.  *
  685.  *************************************************************/
  686.  
  687. boolean handle_explicit_msg( MsgData      * in_data,
  688.                              ServiceType    service,
  689.                              int            in_length,
  690.                              boolean        in_auth ) {
  691.  
  692.     extern  const char * svc_table[ ];       // strings for service type
  693.     byte    response;
  694.     NI_Code ni_error;
  695.  
  696.     num_messages++;
  697.     data_length += ( in_length - 1 );     // not counting code
  698.  
  699.         // if node is off-line and a request message is received
  700.     if( service == REQUEST && !online_flag ) {
  701.         response = ( in_data->exp.code >= NA_foreign_msg ) ?
  702.              NA_foreign_offline : NA_appl_offline;
  703.  
  704.         // return off-line response
  705.         ni_error = ni_send_response( ( MsgData * ) &response, 1 );
  706.         ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
  707.             "sending response" );
  708.     }
  709.     if( report_flag ) {
  710.  
  711.         printf( "Received explicit application message\n" );
  712.         printf( "Service type %s\n", svc_table[ service ] );
  713.         printf( "Message code = 0x%x\n", in_data->exp.code );
  714.         printf( "Authentication %s\n", in_auth ? "on" : "off" );
  715.         printf( "Length = %d\n", in_length );
  716.     }
  717.     return report_flag;
  718. }
  719.  
  720. /*************************************************************
  721.  *
  722.  *      Utility function to return a possibly escaped
  723.  *      NV index from a message.  Used by query/update NV config
  724.  *      and NV fetch network management messages
  725.  *
  726.  *************************************************************/
  727.  
  728. word handle_nv_index( MsgData * in_data, void ** next_byte_ptr ) {
  729.     word nv_index;
  730.  
  731.     byte * msg_data_ptr = in_data->exp.data;
  732.             // point to first data byte of message
  733.  
  734.     nv_index = * msg_data_ptr ++;  // get first byte of message
  735.  
  736.     if( nv_index == 0xFF ) {        // this is an escape sequence
  737.                         // convert Neuron long to Intel word
  738.         swab( ( char * )msg_data_ptr++, ( char * )&nv_index, 2 );
  739.         msg_data_ptr++;            // point past the long
  740.     }
  741.     if( next_byte_ptr ) * next_byte_ptr = msg_data_ptr;
  742.             // return pointer to byte after the index
  743.     return nv_index;
  744. }
  745.  
  746. /*************************************************************
  747.  *
  748.  *            Command to report incoming traffic statistics
  749.  *
  750.  *************************************************************/
  751.  
  752. void traffic( void ) {
  753.  
  754.     printf( "Appl msgs received \t= %u\n", num_messages );
  755.     printf( "Msg data received \t= %lu bytes\n", data_length );
  756.     printf( "NV updates received \t= %u\n", num_updates );
  757.     printf( "NV polls received \t= %u\n", num_polls );
  758.     printf( "Clearing message and NV accumulators\n" );
  759.  
  760.     data_length = num_messages = num_polls = num_updates = 0;
  761. }
  762.  
  763. /*
  764.  ****************************************************************************
  765.  *
  766.  * exit_func().  Process exit command from the keyboard, store NV config
  767.  *
  768.  ****************************************************************************
  769.  */
  770.  
  771. void exit_func( void ) {
  772.  
  773.     int fd;
  774.     unsigned byte_count;
  775.  
  776.     fd = creat( "NVCONFIG.TBL", 0644 );
  777.     if( fd < 0 ) {
  778.         printf( "Unable to open network variable config file\n" );
  779.         exit( 1 );
  780.     }
  781.     byte_count = write( fd, nv_config_table, sizeof( nv_config_table ) );
  782.     if( byte_count != sizeof( nv_config_table ) ) {
  783.         printf( "Unable to write to network variable config file\n" );
  784.         close( fd );
  785.         exit( 1 );
  786.     }
  787.     close( fd );
  788.     ni_close( );
  789.     printf("Leaving the Host Application program.\n");
  790.     exit( 0 );
  791. }
  792.  
  793. /*************************************************************
  794.  *
  795.  *          Load NV config table from disk
  796.  *
  797.  *************************************************************/
  798.  
  799. void load_NV_config( void ) {       // called from main() startup code
  800.     int fd;
  801.     unsigned byte_count;
  802.  
  803.     fd = open( "NVCONFIG.TBL", O_RDONLY );
  804.     if( fd < 0 ) return;        // No file yet
  805.     byte_count = read( fd, nv_config_table, sizeof( nv_config_table ) );
  806.     if( byte_count == sizeof( nv_config_table ) ) {     // success
  807.         printf( "Network variable config table loaded\n" );
  808.         close( fd );
  809.         return;
  810.     }
  811.     printf( "Unable to load NV config table from file\n" );
  812.     close( fd );
  813. }
  814.  
  815. /*************************************************************
  816.  *
  817.  *          get_nv_index - prompt user to enter NV index
  818.  *
  819.  *************************************************************/
  820.  
  821. int get_nv_index( boolean in_only ) {   // returns -1 if invalid
  822.  
  823.     static const char * dir_string[ 2 ] = { "IN ", "OUT" };
  824.     int nv_index;
  825.     network_variable * nv_value_ptr;
  826.  
  827.     nv_value_ptr = nv_value_table;
  828.         // list all the network variables - menu label is index+1
  829.  
  830.     for( nv_index = 0; nv_index < NUM_NVS; nv_index++, nv_value_ptr++ ) {
  831.         if( in_only && nv_value_ptr->direction != NV_IN ) continue;
  832.                              // don't list if not asked for
  833.         printf( "%d. \t%s\t%s\t", nv_index + 1,
  834.             dir_string[ nv_value_ptr->direction ], nv_value_ptr->name );
  835.         nv_value_ptr->print_func( nv_value_ptr->data );       // print value
  836.     }
  837.  
  838.     nv_index = get_integer( "Enter NV number :", 0 ) - 1;
  839.     // If user enters 0 (the default), return error
  840.  
  841.     if( nv_index >= NUM_NVS || nv_index < 0 ) {
  842.         printf( "Invalid NV number\n" );
  843.         return -1;
  844.     }
  845.  
  846.     nv_value_ptr = &nv_value_table[ nv_index ];
  847.     if( in_only && nv_value_ptr->direction != NV_IN ) {
  848.         printf( "Invalid direction\n" );
  849.         return -1;
  850.     }
  851.     return nv_index;
  852. }
  853.  
  854. /*************************************************************
  855.  *
  856.  *          Command to poll an input network variable
  857.  *
  858.  *************************************************************/
  859.  
  860. void NV_poll( void ) {
  861.  
  862.     int                 nv_index, ta_nv_index;
  863.     NI_Code             ni_error;
  864.     ComplType           completion;
  865.     int                 num_responses;
  866.     int                 in_length;
  867.     SendAddrDtl         out_addr;
  868.     MsgData             in_data, out_data;
  869.     nv_struct           * nv_cnfg_ptr;
  870.     network_variable    * nv_value_ptr;
  871.  
  872.     printf( "Which input network variable do you wish to poll?\n" );
  873.     nv_index = get_nv_index ( TRUE );      // get index of NV from user
  874.     if( nv_index < 0 || ! online_flag ) return;
  875.                 // all done if NV not found, or node is off-line
  876.     nv_cnfg_ptr = &nv_config_table[ nv_index ];   // point to cnfg table
  877.  
  878.     // make an outgoing request message to poll the NV
  879.     out_data.unv.direction = NV_OUT;        // to match the receiver(s)
  880.     out_data.unv.NV_selector_hi = nv_cnfg_ptr->selector_hi;
  881.     out_data.unv.NV_selector_lo = nv_cnfg_ptr->selector_lo;
  882.     out_data.unv.must_be_one = 1;
  883.  
  884.     if( nv_cnfg_ptr->addr_index != NULL_IDX ) {     // NV is bound
  885.  
  886.         out_addr.im.type = IMPLICIT;
  887.         out_addr.im.msg_tag = nv_cnfg_ptr->addr_index;
  888.             // For implicit addressing, use configured address table entry
  889.  
  890.         ni_error = ni_send_msg_wait(
  891.             REQUEST,
  892.             & out_addr,             // destination address
  893.             & out_data,
  894.             2,                      // size of selector
  895.             nv_cnfg_ptr->priority,
  896.             nv_cnfg_ptr->auth,
  897.             & completion,
  898.             & num_responses,
  899.             NULL,                   // response address
  900.             & in_data,              // first response data
  901.             & in_length );            // input length
  902.  
  903.         if( handle_error( ni_error, completion, NO_CHECK,
  904.                 "polling NV" ) ) return;
  905.  
  906.         if( num_responses ) for( ;; ) {       // handle responses, if any
  907.  
  908.             handle_netvar_poll_response( & in_data.unv, in_length,
  909.                 nv_index );
  910.             // update the value if a valid response
  911.  
  912.             if( !--num_responses ) break;
  913.  
  914.             ni_error = ni_get_next_response(      // get another, if a group
  915.                 NULL,            // response address
  916.                 & in_data,       // response data
  917.                 & in_length );
  918.             if( handle_error( ni_error, completion, NO_CHECK,
  919.                 "polling NV" ) ) return;
  920.         }
  921.     }
  922.     if( !nv_cnfg_ptr->turnaround ) return;
  923.             // all done if not a turnaround
  924.  
  925.     // get the value of the matching output
  926.     ta_nv_index = match_nv_cnfg( &out_data.unv );
  927.     if( ta_nv_index < 0 ) return;       // no match
  928.  
  929.     nv_value_ptr = &nv_value_table[ ta_nv_index ]; // point to NV value table
  930.     update_nv_value( nv_index, nv_value_ptr->data, nv_value_ptr->size );
  931. }
  932.  
  933. /*************************************************************
  934.  *
  935.  *          Command to update a network variable
  936.  *
  937.  *************************************************************/
  938.  
  939. void NV_update( void ) {
  940.  
  941.     network_variable    * nv_value_ptr;
  942.     nv_struct           * nv_cnfg_ptr;
  943.     int                 nv_index;
  944.     int                 out_length;
  945.     NI_Code             ni_error;
  946.     ComplType           completion;
  947.     SendAddrDtl         out_addr;
  948.     MsgData             out_data;
  949.  
  950.     printf( "Which network variable do you wish to update?\n" );
  951.     nv_index = get_nv_index ( FALSE );    // get NV index from user
  952.     if( nv_index < 0 ) return;
  953.  
  954.     nv_value_ptr = &nv_value_table[ nv_index ];    // point to value table
  955.     printf( "Enter data for %s :", nv_value_ptr->name );
  956.     nv_value_ptr->read_func( nv_value_ptr->data );  // get NV data from user
  957.  
  958.     if( nv_value_ptr->direction == NV_IN || ! online_flag ) return;
  959.             // all done if an input or node is not on-line
  960.  
  961.     // make an outgoing NV update message
  962.  
  963.     nv_cnfg_ptr = &nv_config_table[ nv_index ]; // point to config table
  964.  
  965.     out_data.unv.direction = NV_IN;     // to match the receiver
  966.     out_data.unv.NV_selector_hi = nv_cnfg_ptr->selector_hi;
  967.     out_data.unv.NV_selector_lo = nv_cnfg_ptr->selector_lo;
  968.     out_data.unv.must_be_one = 1;
  969.  
  970.     out_length = nv_value_ptr->size;
  971.     memcpy( out_data.unv.data, nv_value_ptr->data, out_length );
  972.     out_length += 2;        // add selector size to send
  973.  
  974.     if( nv_cnfg_ptr->addr_index != NULL_IDX ) {     // NV is bound
  975.  
  976.         out_addr.im.type = IMPLICIT;        // use the address table for dest
  977.         out_addr.im.msg_tag = nv_cnfg_ptr->addr_index;
  978.  
  979.         ni_error = ni_send_msg_wait(
  980.             nv_cnfg_ptr->service,   // use configured service type
  981.             & out_addr,             // destination address
  982.             & out_data,
  983.             out_length,             // including selector
  984.             nv_cnfg_ptr->priority,
  985.             nv_cnfg_ptr->auth,
  986.             & completion,
  987.             NULL,                   // num_responses
  988.             NULL,                   // response address
  989.             NULL,                   // response data
  990.             NULL );                 // input length
  991.         ( void )handle_error( ni_error, completion, NO_CHECK,
  992.                 "updating NV" );
  993.     }
  994.     if( !nv_cnfg_ptr->turnaround ) return; // all done if not a turnaround
  995.      // find the matching input NV
  996.     ( void ) handle_netvar_msg( & out_data, UNACKD, out_length, TRUE );
  997. }
  998.  
  999.  
  1000. /*************************************************************
  1001.  *
  1002.  *         User interface routines for SNVTs
  1003.  *
  1004.  *************************************************************/
  1005.  
  1006. void print_asc( byte * data ) {     // print a value of type SNVT_str_asc
  1007.     printf( "\"%s\"\n", data );
  1008. }
  1009.  
  1010. void print_cont( byte * data ) {    // print a value of type SNVT_lev_cont
  1011.     printf( "%g percent\n", * data / 2.0 );
  1012. }
  1013.  
  1014. void print_disc( byte * data ) {    // print a value of type SNVT_lev_disc
  1015.  
  1016.     switch ( * data ) {
  1017.         case 0: printf( "OFF\n" );    return;
  1018.         case 1: printf( "LOW\n" );    return;
  1019.         case 2: printf( "MEDIUM\n" ); return;
  1020.         case 3: printf( "HIGH\n" );   return;
  1021.         case 4: printf( "ON\n" );     return;
  1022.         default: printf( "Invalid discrete value %d\n", * data );
  1023.     }
  1024. }
  1025.  
  1026. void print_float( byte * data ) {   // print a value of type SNVT_xxx_f
  1027.     union {
  1028.         float   intel_float;
  1029.         byte    neuron_float[ 4 ];
  1030.     } swapper;
  1031.     int   i;
  1032.  
  1033.     for( i = 3; i >= 0; i-- )
  1034.         swapper.neuron_float[ i ] = * data++;       // reverse byte order
  1035.     printf( "%.5G\n", swapper.intel_float );
  1036. }
  1037.  
  1038. void read_asc( byte * data ) {      // read a value of type SNVT_str_asc
  1039.     char input_buf[ 80 ];
  1040.  
  1041.     gets( input_buf );
  1042.     memset( data, 0, 31 );                       // null it out
  1043.     strncpy( ( char * )data, input_buf, 31 );    // copy up to 31 bytes
  1044. }
  1045.  
  1046. void read_disc( byte * data ) {    // read a value of type SNVT_lev_disc
  1047.     char ch;
  1048.     for( ;; ) {
  1049.         printf( "\nO(F)F, (L)OW, (M)EDIUM, (H)IGH or O(N) :" );
  1050.         ch = getche( );
  1051.         switch( toupper( ch ) ) {
  1052.             case 'F':  * data = 0; break;
  1053.             case 'L':  * data = 1; break;
  1054.             case 'M':  * data = 2; break;
  1055.             case 'H':  * data = 3; break;
  1056.             case 'N':  * data = 4; break;
  1057.             default : printf( " -- invalid choice" ); continue;
  1058.         }
  1059.         printf( "\n" );
  1060.         return;
  1061.     }
  1062. }
  1063.  
  1064. void read_cont( byte * data ) {         // read a value of type SNVT_lev_cont
  1065.     * data = 2 * get_integer( "(percent) ", * data / 2 );
  1066. }
  1067.  
  1068. void read_float( byte * data ) {   // read a value of type SNVT_xxx_f
  1069.     union {
  1070.         float   intel_float;
  1071.         byte    neuron_float[ 4 ];
  1072.     } swapper;
  1073.     int   i;
  1074.     char  input_buf[ 80 ];
  1075.  
  1076.     for( ;; ) {
  1077.         gets( input_buf );
  1078.         if( sscanf( input_buf, "%g", &swapper.intel_float ) == 1 ) break;
  1079.         printf( "Invalid floating point data\n" );
  1080.     }
  1081.  
  1082.     for( i = 3; i >= 0; i-- )
  1083.         * data ++ = swapper.neuron_float[ i ];       // reverse byte order
  1084. }
  1085.